package cn.w2.server;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.NettyRuntime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/// 启动服务器
public class StartServer {

	private static final Logger LOG = LoggerFactory.getLogger(StartServer.class);
	// 主线程池执行器
	private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
	// 子线程池执行器
	private final EventLoopGroup workerGroup = new NioEventLoopGroup(NettyRuntime.availableProcessors());

	private final int port;

	public StartServer(int port) {
		this.port = port;
	}

	public static void main(String[] args) {
		int port = 8081;
		try {
			new StartServer(port).start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void start() throws Exception {
		LOG.debug("开始启动服务器...");
		final W2ServerHandler w2ServerHandler = new W2ServerHandler();

		try {
			// 它允许轻松引导ServerChannel
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					/// 用于从中创建Channel实例的Class
					.channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
					.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
					.option(ChannelOption.SO_BACKLOG, 128)
					.option(ChannelOption.SO_KEEPALIVE, true)
					// 在ServerBootstrap中添加这些选项
					.option(ChannelOption.SO_REUSEADDR, true)
					.childOption(ChannelOption.TCP_NODELAY, true)
					.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
					// 添加一个EchoServerHandler 到子Channel的 ChannelPipeline
					.childHandler(new ChannelInitializer<SocketChannel>() {
						/// 处理 I/O 事件或拦截 I/O 操作，并将其转发到其ChannelPipeline下一个处理程序
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ch.pipeline().addLast(new IdleStateHandler(0, 0, 60)); // 心跳检测
							/// EchoServerHandler 被标注为@Shareable，所以我们可以总是使用同样的实例
							ch.pipeline().addLast(w2ServerHandler);
						}
					});
			/// 异步地绑定服务器；调用 sync()方法阻塞等待直到绑定完成
			ChannelFuture f = b.bind().sync();
			/// 获取 Channel 的CloseFuture，并且阻塞当前线程直到它完成
			f.channel().closeFuture().sync();
		} finally {
			bossGroup.shutdownGracefully().sync();
			workerGroup.shutdownGracefully();
		}
	}

}
